package main

import (
	"fmt"
	"sync"
)

func main() {
	// 初始化 sync.Map 在 Go 语言中， sync.Map 的 key 和 value 类型没有特定的限制
	var m sync.Map

	// 1. 存储键值对 (Store) 存储键值对，线程安全。键和值的类型都是 interface{}
	m.Store("name", "Go")
	m.Store("version", "1.21")
	m.Store("is_good", true)

	// 2. 读取键值对 (Load)
	if value, ok := m.Load("name"); ok {
		fmt.Printf("name: %v\n", value) // 输出: name: Go
	}

	// 3. 读取不存在的键
	if _, ok := m.Load("author"); !ok {
		fmt.Println("author 不存在")
	}

	// 4. 加载或存储 (LoadOrStore)
	// 如果键存在则返回已有的值，否则存储新值
	if value, loaded := m.LoadOrStore("version", "1.20"); loaded {
		fmt.Printf("version 已存在: %v\n", value) // 输出: version 已存在: 1.21
	} else {
		fmt.Printf("version 存储成功: %v\n", value)
	}

	// 5. 删除键 (Delete)
	m.Delete("is_good")
	if _, ok := m.Load("is_good"); !ok {
		fmt.Println("is_good 已被删除")
	}

	// 6. 遍历所有键值对 (Range)
	// Range 接收一个函数作为参数，遍历过程中会为每个键值对调用该函数
	// Range 遍历的是一个快照，可能不包含遍历过程中新增的键。
	//遍历顺序是随机的，不保证与插入顺序一致。
	fmt.Println("\n遍历所有键值对:")
	m.Range(func(key, value interface{}) bool {
		fmt.Printf("%v: %v\n", key, value)
		// 返回 true 继续遍历，返回 false 停止遍历
		return true
	})

	// 7. 并发读写测试
	concurrentTest()
}

// 并发读写测试
func concurrentTest() {
	var m sync.Map
	var wg sync.WaitGroup

	// 启动10个goroutine写入数据
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go func(id int) {
			defer wg.Done()
			key := fmt.Sprintf("key%d", id)
			m.Store(key, id)
			fmt.Printf("写入: %s -> %d\n", key, id)
		}(i)
	}

	// 启动10个goroutine读取数据
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go func(id int) {
			defer wg.Done()
			key := fmt.Sprintf("key%d", id)
			if value, ok := m.Load(key); ok {
				fmt.Printf("读取: %s -> %v\n", key, value)
			} else {
				fmt.Printf("读取: %s 不存在\n", key)
			}
		}(i)
	}

	wg.Wait()
	fmt.Println("并发测试完成")
}
